package com.ygl.strategy.service.interceptor;

import com.ygl.common.constant.DiscoveryConstant;
import com.ygl.core.adapter.AbstractCoreAdapter;
import com.ygl.strategy.service.filter.ServiceStrategyRouteFilter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * author: yanggld
 * date: 2019/12/22 15:39
 * version: 1.0
 * description: RestTemplateStrategyInterceptor
 */
@Slf4j
public class RestTemplateStrategyInterceptor extends AbstractStrategyInterceptor implements ClientHttpRequestInterceptor {

    @Autowired
    private ServiceStrategyRouteFilter serviceStrategyRouteFilter;

    protected List<String> requestHeaderList = new ArrayList<>();

    public RestTemplateStrategyInterceptor(String contextRequestHeaders, String businessRequestHeaders) {
        super(contextRequestHeaders, businessRequestHeaders);

        log.info("------- RestTemplate Intercept Information -------");
        log.info("RestTemplate desires to intercept customer headers are {}", requestHeaderList);
        log.info("--------------------------------------------------");
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
//        interceptInputHeader();

        // 加入自定义字段
        applyInnerHeader(request);
        applyOuterHeader(request);

//        if (CollectionUtils.isNotEmpty(restTemplateStrategyInterceptorAdapterList)) {
//            for (RestTemplateStrategyInterceptorAdapter restTemplateStrategyInterceptorAdapter : restTemplateStrategyInterceptorAdapterList) {
//                restTemplateStrategyInterceptorAdapter.intercept(request, body, execution);
//            }
//        }
//
//        interceptOutputHeader(request);
        // 请求继续被执行
        return execution.execute(request, body);
    }

    private void applyInnerHeader(HttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        headers.add(DiscoveryConstant.N_D_SERVICE_GROUP, coreAdapter.getGroup());
//        if (strategyTraceEnabled) {
//            headers.add(DiscoveryConstant.N_D_SERVICE_ID, coreAdapter.getServiceId());
//            headers.add(DiscoveryConstant.N_D_SERVICE_ADDRESS, coreAdapter.getHost() + ":" + coreAdapter.getPort());
//            headers.add(DiscoveryConstant.N_D_SERVICE_VERSION, coreAdapter.getVersion());
//            headers.add(DiscoveryConstant.N_D_SERVICE_REGION, coreAdapter.getRegion());
//            headers.add(DiscoveryConstant.N_D_SERVICE_ENVIRONMENT, coreAdapter.getEnvironment());
//        }
    }

    private void applyOuterHeader(HttpRequest request) {
        ServletRequestAttributes attributes = serviceStrategyContextHolder.getRestAttributes();
        if (attributes == null) {
            return;
        }

        HttpServletRequest previousRequest = attributes.getRequest();
        Enumeration<String> headerNames = previousRequest.getHeaderNames();
        if (headerNames == null) {
            return;
        }

        HttpHeaders headers = request.getHeaders();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = previousRequest.getHeader(headerName);
            boolean isHeaderContains = isHeaderContainsExcludeInner(headerName.toLowerCase());
            if (isHeaderContains) {
                headers.add(headerName, headerValue);
            }
        }

        if (CollectionUtils.isEmpty(headers.get(DiscoveryConstant.N_D_VERSION))) {
            String routeVersion = serviceStrategyRouteFilter.getRouteVersion();
            if (StringUtils.isNotEmpty(routeVersion)) {
                headers.add(DiscoveryConstant.N_D_VERSION, routeVersion);
            }
        }
        if (CollectionUtils.isEmpty(headers.get(DiscoveryConstant.N_D_REGION))) {
            String routeRegion = serviceStrategyRouteFilter.getRouteRegion();
            if (StringUtils.isNotEmpty(routeRegion)) {
                headers.add(DiscoveryConstant.N_D_REGION, routeRegion);
            }
        }
        if (CollectionUtils.isEmpty(headers.get(DiscoveryConstant.N_D_VERSION_WEIGHT))) {
            String routeVersionWeight = serviceStrategyRouteFilter.getRouteVersionWeight();
            if (StringUtils.isNotEmpty(routeVersionWeight)) {
                headers.add(DiscoveryConstant.N_D_VERSION_WEIGHT, routeVersionWeight);
            }
        }
        if (CollectionUtils.isEmpty(headers.get(DiscoveryConstant.N_D_REGION_WEIGHT))) {
            String routeRegionWeight = serviceStrategyRouteFilter.getRouteRegionWeight();
            if (StringUtils.isNotEmpty(routeRegionWeight)) {
                headers.add(DiscoveryConstant.N_D_REGION_WEIGHT, routeRegionWeight);
            }
        }
    }

    protected boolean isHeaderContainsExcludeInner(String headerName) {
        return isHeaderContains(headerName) &&
                !StringUtils.equals(headerName, DiscoveryConstant.N_D_SERVICE_GROUP) &&
                !StringUtils.equals(headerName, DiscoveryConstant.N_D_SERVICE_TYPE) &&
                !StringUtils.equals(headerName, DiscoveryConstant.N_D_SERVICE_ID) &&
                !StringUtils.equals(headerName, DiscoveryConstant.N_D_SERVICE_ADDRESS) &&
                !StringUtils.equals(headerName, DiscoveryConstant.N_D_SERVICE_VERSION) &&
                !StringUtils.equals(headerName, DiscoveryConstant.N_D_SERVICE_REGION) &&
                !StringUtils.equals(headerName, DiscoveryConstant.N_D_SERVICE_ENVIRONMENT);
    }
    protected boolean isHeaderContains(String headerName) {
        return headerName.startsWith(DiscoveryConstant.N_D_PREFIX) || requestHeaderList.contains(headerName);
    }

}
